import tortoise.fields.relational
from tortoise.models import Model
from tortoise import fields, Tortoise
from typing import Any
import datetime
import logging

from config import config

logger = logging.getLogger(__name__)


class Customers(Model):
    """
    Customer model mapped to the 'customer' table in the database.
    """
    id = fields.IntField(pk=True, generated=True)
    name = fields.CharField(max_length=50, description="Customer Name")
    phone = fields.CharField(max_length=14, default="None")
    address = fields.CharField(max_length=200)
    presenter = fields.CharField(max_length=30, default="我")
    register_time = fields.DatetimeField(auto_now_add=True)
    note = fields.TextField(default="None")

    def __repr__(self):
        return "Customers(id={}, name={}, phone={}, address={}, presenter={}, lastLoginTime={}, note={})".format(
            self.id, self.name, self.phone, self.address, self.presenter, self.register_time, self.note
        )

    def __eq__(self, other: Any) -> bool:
        if not isinstance(other, self.__class__):
            return False
        return (self.name == other.name and self.address == other.address and
                self.phone == other.phone and self.presenter == other.presenter) or \
            (self.id is not None and other.id is not None and self.id == other.id)


class Users(Model):
    """
    User model mapped to the 'users' table in the database.
    """
    id = fields.IntField(pk=True, generated=True)
    name = fields.CharField(max_length=50)
    address = fields.CharField(max_length=200)
    # wx_user_id = fields.CharField(max_length=100, unique=True)  这个不是唯一标识符，弃用
    nickname = fields.CharField(max_length=100, unique=True)
    phone = fields.CharField(max_length=27, default='None')
    password_hashed = fields.CharField(max_length=255, default='None')
    register_time = fields.DatetimeField(auto_now_add=True)
    role = fields.CharField(max_length=30, default='MANAGER')
    note = fields.TextField(default='NULL')
    is_deleted = fields.BooleanField(default=False)

    def __repr__(self):
        return "Users(id={}, name={}, phone={}, password_hashed={}, register_time={}, role={}, note={})".format(
            self.id, self.name, self.phone, self.password_hashed, self.register_time, self.role, self.note
        )


class Kumquats(Model):
    """
    Kumquat model mapped to the 'kumquat' table in the database.
    """
    id = fields.IntField(pk=True, generated=True)
    name = fields.CharField(max_length=5)
    packing = fields.CharField(max_length=5, default='0')  # Not used
    format = fields.CharField(max_length=5)
    original_price = fields.DecimalField(max_digits=5, decimal_places=2, default=0)
    price = fields.DecimalField(max_digits=5, decimal_places=2, default=0)
    users = fields.ForeignKeyField("models.Users", related_name='kumquats')
    # profit = fields.DecimalField(max_digits=5, decimal_places=2, default=0)
    pricing_date = fields.DateField(auto_now=True, default=datetime.datetime.now(datetime.UTC).date())
    note = fields.TextField(default='')

    def __repr__(self):
        return "Kumquat(id={}, name={}, format={}, original_price={}, price={}, users={}, pricing_date={}, " \
               "note={})".format(
            self.id, self.name, self.format, self.original_price, self.price, self.users,
            self.pricing_date, self.note
        )
    @staticmethod
    def to_str(kumquat:Any):
        if isinstance(kumquat, Kumquats):
            return "🍊名称：【{} {}】 \n🍊售价：【{}】".format(kumquat.name, kumquat.format, kumquat.price)
        else:
            return "{}".format(kumquat)


class Order(Model):
    """
    Order model mapped to the 'order' table in the database.
    """
    id = fields.IntField(pk=True, generated=True)
    customers = fields.ForeignKeyField("models.Customers", related_name='order')
    kumquats = fields.ForeignKeyField("models.Kumquats", related_name='order')
    users = fields.ForeignKeyField("models.Users", related_name='order')
    quantity = fields.IntField()
    on_sold = fields.DecimalField(max_digits=3, decimal_places=2, default=1)
    amount = fields.DecimalField(max_digits=10, decimal_places=2, default=0)
    book_date = fields.DatetimeField(default=datetime.datetime.now().strftime(config.DEFAULT_TIME_FORMAT))
    status = fields.CharField(max_length=10, default='已下单')
    order_delivery_code = fields.CharField(max_length=20, default='None')
    note = fields.TextField(null=True, default='CURRENT')

    def __repr__(self):
        return "Order(id={}, customer={}, kumquat={}, quantity={}, amount={}, book_date={}, status={}, note={})".format(
            self.id, self.customers, self.kumquats, self.quantity, self.amount, self.book_date, self.status,
            self.note
        )

    def __str__(self):
        print("Order(id={}, customer={}, kumquat={}, quantity={}, amount={}, book_date={}, status={}, note={})".format(
            self.id, self.customers, self.kumquats, self.quantity, self.amount, self.book_date, self.status,
            self.note
        ))

    @staticmethod
    def to_str(order: Any):
        if isinstance(order, Order):
            return "🍊客户：{}-{}-{} \n🍊商品：{} {} \n🍊数量：{} \n🍊金额：{} \n🍊备注：{}".format(
                order.customers.name, order.customers.address, order.customers.phone,
                order.kumquats.name, order.kumquats.format,
                order.quantity, order.amount, order.note
            )
        else:
            return "{}".format(order)

    def get_amount(self):
        if not isinstance(self.kumquats, Kumquats):
            raise RuntimeError("kumquats is Not define, can not calculate the price!")
        amount = self.kumquats.price * self.quantity * self.on_sold
        self.amount = amount if '赠送' not in self.note else self.kumquats.original_price * self.quantity * -1


class Chat(Model):
    """
    Chat model mapped to the 'chat' table in the database.
    """
    id = fields.IntField(pk=True, generated=True)
    user = fields.ForeignKeyField("models.Users", related_name='chat')
    query = fields.TextField()
    answer = fields.TextField()
    ai_answer = fields.TextField(default="['']")
    query_time = fields.DatetimeField(default=datetime.datetime.now().strftime(config.DEFAULT_TIME_FORMAT))
    answer_time = fields.DatetimeField(auto_now=True)
    actions = fields.TextField()
    raw_msg = fields.TextField()
    note = fields.TextField(null=True, default='')

    def __repr__(self):
        return "Chat(id={}, user={}, query={}, answer={}, ai_answer={}, query_time={}, answer_time={}, " \
               "actions={}, raw_msg={}, note={})".format(
            self.id, self.user, self.query, self.answer, self.ai_answer,
            self.query_time, self.answer_time, self.actions, self.raw_msg, self.note
        )

    def is_group(self):
        return self.raw_msg.get('is_group')


class ChatRecord(Model):
    """
    ChatRecord mapped all the chat content data
    """
    id = fields.IntField(pk=True, generated=True)
    from_nickname = fields.CharField(max_length=50)
    is_group = fields.BooleanField()
    content = fields.TextField()
    chat_id = fields.IntField()  # related to Chat.id, but not constraint

    def __repr__(self):
        return "ChatRecord(id={}, from_nickname={}, is_group={}, content={}, chat_id={})".format(
            self.id, self.from_nickname, self.is_group, self.content, self.chat_id
        )


async def init_db():
    """
    Initialize the database.
    """
    await Tortoise.init(config=config.TORTOISE_ORM)
    await Tortoise.generate_schemas()
    admin_exists = await Users.exists(id=0)
    anonym_exists = await Users.exists(id=1)
    if not admin_exists:
        await Users.create(id=0, name='admin', phone='None', password_hashed='None',
                           nickname='kumquat king robot admin', role='ADMIN', address='None')
    if not anonym_exists:
        await Users.create(id=1, name='anonym', phone='None', password_hashed='None',
                           nickname='**陌生人Anonymous**', role='ANONYMOUS', address='None', note='Anonymous user')

    import pandas as pd
    default_kumquats = pd.read_csv('./data/templates/default_kumquat.csv')
    default_kumquats['note'] = 'CURRENT'
    default_kumquats['pricing_date'] = datetime.datetime.now().date().strftime(config.DEFAULT_DATE_FORMAT)
    default_kumquats['users_id'] = 0
    default_kumquats['id'] = range(1, len(default_kumquats) + 1)
    to_insert = []
    for _, row in default_kumquats.iterrows():
        to_insert.append(Kumquats(**row.to_dict()))
        if await Kumquats.exists(id=row['id']):
            continue
        else:
            await Kumquats.create(**row.to_dict())
    logger.info('[Init DB] Database initialized successfully. Admin user, default kumquat created.')
